package com.codefish.framework.spring.context.support;

import com.codefish.framework.spring.beans.exception.BeansException;
import com.codefish.framework.spring.beans.exception.NoSuchBeanDefinitionException;
import com.codefish.framework.spring.beans.factory.DefaultListableBeanFactory;
import com.codefish.framework.spring.beans.factory.config.IBeanFactoryPostProcessor;
import com.codefish.framework.spring.beans.factory.config.IConfigurableListableBeanFactory;
import com.codefish.framework.spring.beans.factory.xml.XmlBeanDefinitionReader;
import com.codefish.framework.spring.core.io.Resource;

import java.util.ArrayList;
import java.util.List;

/**
 * 从classpath中加载xml文件中的bean的ApplicationContext类
 *
 * @author <a href='https://gitee.com/hzf2281'>codefish</a>
 * @version 1.0.0
 * @since 2022/10/04 上午 10:55
 */
public class ClassPathXmlApplicationContext extends AbstractApplicationContext {
    /**
     * 被包装的beanFactory，典型的装饰者模式
     */
    private DefaultListableBeanFactory beanFactory;
    /**
     * 资源Resource列表
     */
    private final List<Resource> configureResources;


    public ClassPathXmlApplicationContext(String[] paths) {
        //创建beanFactory
        this.beanFactory = new DefaultListableBeanFactory();
        //从所有classPath加载resource
        this.configureResources = new ArrayList<>();
        for (String classPath : paths) {
            this.configureResources.add(getResource(classPath));
        }
        //初始化beanFactory
        refresh();
    }


    /**
     * 加载资源中的BeanDefinition到beanFactory
     *
     * @param beanFactory 目标beanFactory
     */
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
        XmlBeanDefinitionReader bdReader = new XmlBeanDefinitionReader(beanFactory);
        for (Resource configureResource : configureResources) {
            bdReader.loadBeanDefinitions(configureResource);
        }
    }


    // ------------------------------------
    // ---  以下方法重写了父类暴露的钩子方法 ----
    //--------------------------------------

    @Override
    protected void refreshBeanFactory() throws BeansException, IllegalStateException {
        // 加载资源中的BeanDefinition到beanFactory
        loadBeanDefinitions(this.beanFactory);
        //将beanFactory中定义的BeanFactoryPostProcessor注册
        List<String> fppNames = this.beanFactory.getBeanNamesForType(IBeanFactoryPostProcessor.class);
        for (String fppName : fppNames) {
            IBeanFactoryPostProcessor fpp = this.beanFactory.getBean(fppName, IBeanFactoryPostProcessor.class);
            addBeanFactoryPostProcessor(fpp);
        }

    }

    @Override
    protected void closeBeanFactory() {
        DefaultListableBeanFactory beanFactory = this.beanFactory;
        if (beanFactory != null) {
            this.beanFactory = null;
        }
    }

    @Override
    public IConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException {
        return this.beanFactory;
    }
}
